import json
from logger import logger_main
from typing import Dict, List
from dataclasses import dataclass
from collections import defaultdict
from config import IGNORE_USER_LIST
from typing import Literal
from enum import Enum, auto


class MSG_TYPE(Enum):
    """消息类型枚举"""
    TEXT = auto()
    IMAGE = auto()
    VOICE = auto()
    VIDEO = auto()
    EMOJI = auto()
    INVITE = auto()
    PAT = auto()


@dataclass
class ReceivedMessage:
    message_id: int
    from_user_wx_id: str
    to_user_wx_id: str
    message_type: int
    send_user_wx_id: str
    send_user_nickname: str
    content: str
    push_content: str
    create_time: int


@dataclass
class RoomMessageDetail:
    """
    表示聊天室中的一条消息详情。

    role: 消息的发送者角色，限定为 'user'（用户）或 'assistant'（助手/系统）。\

    message_id: 消息的唯一标识符，通常为整数。

    message_type: 消息类型代码，例如：1 (文本), 2 (图片), 3 (语音) 等。

    content: 消息的主要内容，如文本消息的正文。

    create_time: 消息创建时的 Unix 时间戳（秒或毫秒级）。

    update_time: 消息最后更新时的 Unix 时间戳。

    send_user_nickname: 发送消息的用户的昵称。默认值为 "未知用户"。

    is_withdrawn: 标识消息是否已被撤回。默认值为 False（未撤回）。

    extra_content: 额外的内容或元数据，用于存储非标准消息格式的数据。默认值为 None。

    emoji_base64: 如果消息包含表情，此处存储表情的 Base64 编码字符串。默认值为 None。

    image_base64: 如果消息包含图片，此处存储图片的 Base64 编码字符串。默认值为 None。
    """
    role: Literal["user", "assistant"]
    message_id: int | None
    message_type: int
    content: str
    create_time: int
    update_time: int
    send_user_nickname: str = "未知用户"
    is_withdrawn: bool = False
    extra_content: str | None = None
    emoji_base64: str | None = None
    image_base64: str | None = None


# 消息字典
RCV_MSG_STASH: Dict[int, ReceivedMessage] = {}

# 房间消息字典
ROOM_MESSAGE_DICT: Dict[str, List[RoomMessageDetail]] = defaultdict(list)

# 用户昵称字典
USER_NAME_MAP: Dict[str, str] = {}


def _extract_nickname_from_push_content(push_content: str) -> str | None:
    """从推送内容中提取昵称"""
    colon_index = push_content.find(":")
    if colon_index != -1:
        return push_content[:colon_index].strip()

    # 处理特殊格式
    for pattern in ["在群聊中发了一个表情", "在群聊中发了一张图片", "在群聊中@了你", "在群聊中发了一段视频"]:
        if pattern in push_content:
            return push_content.replace(pattern, "").strip()
    return None


def _parse_content(content: str) -> tuple[str, str]:
    """解析消息内容,提取微信ID和实际内容"""
    colon_index = content.find(":")
    if colon_index == -1:
        logger_main.warning(f"无法解析消息内容格式: {content}")
        return "", content

    wx_id = content[:colon_index].strip()
    real_content = content[colon_index + 1:].strip()
    return wx_id, real_content


def _get_or_update_nickname(wx_id: str, push_content: str) -> str:
    """获取或更新用户昵称"""
    # 先从缓存获取
    nickname = USER_NAME_MAP.get(wx_id)
    logger_main.info(f"尝试从缓存获取用户昵称: {wx_id} -> {nickname}")
    # 如果不存在或是未知用户,尝试从推送内容解析
    if not nickname or nickname == "未知用户":
        nickname = _extract_nickname_from_push_content(push_content)

        if not nickname:
            logger_main.warning(f"⚠️ 无法解析用户昵称, 'PushContent': {push_content}")
            nickname = "未知用户"
        else:
            logger_main.info(f"✅ 成功从消息解析用户昵称: {wx_id} -> {nickname}")
        # 更新缓存
        USER_NAME_MAP[wx_id] = nickname

    return nickname


def push_received_message_stash(message: dict) -> ReceivedMessage | None:
    """解析并存储消息"""
    try:
        message_type = message.get("MsgType", -1)
        from_user_wx_id = message.get("FromUserName", {}).get("string", "")
        send_user_wx_id = from_user_wx_id
        to_user_wx_id = message.get("ToUserName", {}).get("string", "")

        if not from_user_wx_id:
            logger_main.error(
                f"❌ 无法获取消息的发送者，消息内容: {json.dumps(message, ensure_ascii=False, indent=4)}")
            return None
        if from_user_wx_id in IGNORE_USER_LIST:
            logger_main.info(f"消息来自忽略列表中的用户 {from_user_wx_id}，跳过处理。")
            return None
        # 提取基础字段
        message_id = message.get("NewMsgId", {})
        content = message.get("Content", {}).get("string", "")
        push_content = message.get("PushContent", "")
        create_time = message.get("CreateTime", 0)
        # 解析发送者信息
        logger_main.info(
            f"一条来自 {from_user_wx_id} 发来的消息,消息ID: {message_id}")
        if "@chatroom" in from_user_wx_id:
            send_user_wx_id, real_content = _parse_content(content)
        else:
            real_content = content
        nickname = _get_or_update_nickname(
            send_user_wx_id, push_content) if send_user_wx_id else "未知用户"
        # 创建消息详情
        received_message = ReceivedMessage(
            message_id=message_id,
            message_type=message_type,
            from_user_wx_id=from_user_wx_id,
            to_user_wx_id=to_user_wx_id,
            send_user_wx_id=send_user_wx_id,
            send_user_nickname=nickname,
            content=real_content,
            push_content=push_content,
            create_time=create_time
        )
        # 存储消息
        RCV_MSG_STASH[message_id] = received_message
        return received_message
    except Exception as e:
        logger_main.exception(
            f"❌ 存储消息时出错: {e}")
        raise e


def get_received_message_stash(message_id: int) -> ReceivedMessage | None:
    """通过消息ID获取存储的消息"""
    return RCV_MSG_STASH.get(message_id, None)


def push_room_message_stash(from_user_wx_id: str, room_message_detail: RoomMessageDetail):
    """存储房间消息"""
    ROOM_MESSAGE_DICT[from_user_wx_id].append(room_message_detail)


def get_room_message_stash(from_user_wx_id: str) -> List[RoomMessageDetail]:
    """通过房间ID获取存储的房间消息"""
    return ROOM_MESSAGE_DICT.get(from_user_wx_id, [])


def clear_room_message_stash(from_user_wx_id: str):
    """通过房间ID清空存储的房间消息"""
    ROOM_MESSAGE_DICT[from_user_wx_id].clear()


def withdraw_room_message(from_user_wx_id: str, message_id: int, withdraw_time: int):
    """撤回房间消息"""
    messages = ROOM_MESSAGE_DICT.get(from_user_wx_id, [])
    for msg in messages:
        if msg.message_id == message_id:
            msg.is_withdrawn = True
            msg.update_time = withdraw_time
            logger_main.info(
                f"消息已标记为撤回: 房间 {from_user_wx_id}, 消息ID {message_id}, 内容: {msg.content}")
            return


def get_nickname(wx_id: str) -> str:
    """获取用户昵称"""
    return USER_NAME_MAP.get(wx_id, "未知用户")
